const properties = require('properties')


/**
 * 配置类，注解在类上，表示该类的所有属性/访问器作为配置类中的配置
 * @param name
 * @constructor
 */
export function Configuration(target){

}

/**
 * 映射方法到post请求处理器器
 * @param url 请求路径
 * @constructor
 */
export function PostMapping(url?:string){

}

/**
 * 映射方法到get请求处理器器
 * @param url 请求路径
 * @constructor
 */
export function GetMapping(url?:string){

}

/**
 * 映射方法到请求处理器器
 * @param url 请求路径
 * @param method 请求方法
 * @constructor
 */
export function RequestMapping(url?:string, method:string='GET'){

}

/**
 * 该方法为测试方法
 * @param times
 * @constructor
 */
export function Test(times:number=10000){

}

/**
 * 表示该方法的返回值作为http的body响应内容写出
 * @constructor
 */
export function ResponseBody(){

}

/**
 * 表示该类是Rest控制类，该类中的所有方法将作为其请求处理器吧，返回值作为其响应内容
 * @param name
 * @constructor
 */
export function RestController(name?:string):NewableFunction{
    return function(target:FunctionConstructor){

    }
}

/**
 * 自动调度该方法或者该类中的scheduling静态方法
 * @param delay
 * @param fixedRate
 * @param when
 * @constructor
 */
export function Scheduling(fixedRate:number=1, when:Date=null, delay:number=0){
    return function (target, methodName?:string, descriptor?:PropertyDescriptor){
        if(methodName && descriptor){           // 方法
            setInterval(()=>{
                descriptor.value()
            }, fixedRate*1000)
        }
    }
}

/**
 * 表示该请求处理器需要用户的登录态token
 * @param require
 * @constructor
 */
export function RequireLogin(require?:boolean){

}

export function CrossOrigin(){

}

/**
 * 表示该类是一个数据库模型方案，所有属性/访问器会被视作数据库字段
 * @constructor
 */
export function Entity(name?:string):NewableFunction{
    return function (target: FunctionConstructor){
        return
    }
}

/**
 * 表示在该成员上忽略类注解的效果
 * @constructor
 */
export function Ignore(ignore:boolean=true){

}

/**
 * 表示该自动将.properties中的匹配的配置注入配置到该类对应的属性值/访问器上
 * @constructor
 * @param target
 */
export function ConfigurationProperties(target){
    const thisClassName = target.name
    // 标记该类为映射配置文件的属性
    Object.defineProperty(target, '_ConfigurationProperties', {
        configurable:false,
        enumerable:false,
        writable:false,
        value:thisClassName,
    })
}

/**
 * 表示该方法/类/字段/注解/常量会被自动注入到运行时global
 * @constructor
 */
export function AutoWired(target, propertyKey?:string | number | symbol, descriptor?:PropertyDescriptor){
    const thisClassName = target.name
    global[thisClassName] = target
}

/**
 * 表示该函数/类下的所有方法被解释为对应的云函数
 * @constructor
 */
export function CloudFunction(name?:string){

}

/**
 * 表示该方法作为一个独立子服务长期贮存于内存中
 * @param name
 * @constructor
 */
export function Service(name?:string){

}

/**
 * 表示自动为该类的所有属性添加其对应的访问器和对应的get/set方法
 * @constructor
 */
export function Data(targetClass){
    // 实例化默认对象获取字段（注意，尚未实例化该类时，无法获取其字段）
    const temp = Reflect.construct(targetClass, [])
    // 获取除了symbol之外的所有的属性
    for (const property of Object.getOwnPropertyNames(temp)) {
        if(typeof(this[property]) == 'function'){           // 过滤其函数方法
            continue
        }
        Object.defineProperty(targetClass.prototype, `get_${property}`, {
            configurable:false,
            enumerable: true,
            get(): any {
                return ()=>this[property]
            },
        })
        Object.defineProperty(targetClass.prototype, `set_${property}`, {
            configurable:false,
            enumerable: true,
            get(): any {
                return (v)=>this[property] = v
            },
        })
    }
}

/**
 * 表示重写该方法/访问器，如果对应的方法和prototype里面的方法不一致，则会报错
 * @constructor
 */
export function Override(target, methodName:string, descriptor: PropertyDescriptor){
    const parentClass = target.__proto__
    const parentClassName = parentClass.constructor.name
    const thisClassName = target.constructor.name
    console.log(typeof(target.__proto__[methodName]))
    if(typeof(target.__proto__[methodName]) != 'function'){
        throw new Error(`父类'${parentClassName}'没有该'${methodName}'方法，无法在子类'${thisClassName}'中实现重写！'`)
    }
}

/**
 * 表示被修饰的属性是一个常量，不可被随意更改，只能赋予初始值
 * @param target
 * @param propertyKey
 * @param descriptor
 * @constructor
 */
export function Final(target, propertyKey: symbol | number | string, descriptor?:PropertyDescriptor){
    console.log({target, propertyKey})
    const s = "_" + String(propertyKey)
    descriptor = descriptor || Object.getOwnPropertyDescriptor(target, propertyKey)
    console.log("descriptor", descriptor)
    Object.defineProperty(target, propertyKey, {
        configurable:false,
        enumerable:true,
        get(): any {
            return this[s]
        }
    })
}

/**
 * 表示该类不可被重写，保护密封该类，不能为该类添加/删除新的方法,属性,访问器,构造器
 * @constructor
 */
export function Sealed(ctor: any){
    Object.seal(ctor)
    Object.seal(ctor.prototype)
}

/**
 * 配置该方法是否可以被枚举到
 * @param enumerable
 */
export function enumerable(enumerable:boolean=true){
    return function(target:Function, methodName:string, descriptor: PropertyDescriptor){
        descriptor.enumerable = enumerable
    }
}

/**
 * 表示该类是一个全局单例对象，会在该类instance静态访问器挂载一个唯一的实例对象
 * @constructor
 */
export function Singleton(target){
    const thisClassName = target.constructor.name
    // 1. 使用反射Reflect生成一个指定的对象实例
    const singleton = Reflect.construct(target, [])
    console.log({target, singleton})
    // 2. 创建一个static的instance静态访问器
    Object.defineProperty(target, "instance", {
        configurable: false,
        enumerable: true,
        get(): any {
            return singleton
        }
    })
}
